package com.worldcup.service.question.calculator;

import com.worldcup.model.enums.QuestionFormTypeEnum;
import com.worldcup.model.enums.QuestionTypeEnum;
import com.worldcup.model.question.Question;
import com.worldcup.model.question.QuestionOption;
import com.worldcup.model.question.QuestionUserAnswer;
import com.worldcup.service.question.QuestionMatchResultService;
import com.worldcup.service.question.QuestionOptionService;
import com.worldcup.service.question.QuestionService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author duwan.zq
 * @date 2019/03/10
 */
public class MatchResultTask implements Runnable{

    private final static Logger logger = LoggerFactory.getLogger(MatchResultTask.class);

    private final static String OPTION_A = "A";

    private final static String OPTION_E = "E";

    private List<QuestionUserAnswer> answers;

    private List<QuestionUserAnswer> passiveAnswers;

    private QuestionService questionService;

    private QuestionOptionService optionService;

    private QuestionMatchResultService matchResultService;

    private String openid;

    private String passiveOpenid;

    private int priority;

    public MatchResultTask(List<QuestionUserAnswer> answers, List<QuestionUserAnswer> passiveAnswers,  QuestionService questionService,
                           QuestionOptionService optionService, QuestionMatchResultService matchResultService, int priority){
        this.answers = answers;
        this.passiveAnswers = passiveAnswers;
        this.questionService = questionService;
        this.optionService = optionService;
        this.matchResultService = matchResultService;

        openid = this.answers.get(0).getOpenid();
        passiveOpenid = this.passiveAnswers.get(0).getOpenid();
        this.priority = priority;
    }

    @Override
    public void run() {
        Thread.currentThread().setPriority(priority);
        Thread.currentThread().setName("user-answer-" + openid + "-" + passiveOpenid);
        logger.info("提交user任务, openid = {}, passiveOpenid = ", openid, passiveOpenid);
        //passiveAnswers按questionId分组
        Map<Long,List<QuestionUserAnswer>> passiveAnswerMap = passiveAnswers.stream().collect(Collectors.groupingBy(QuestionUserAnswer::getQuestionId));
        BigDecimal harmonyScore = BigDecimal.ZERO;
        BigDecimal topicScore = BigDecimal.ZERO;
        List<String> commonIdols = new ArrayList<>();
        List<String> commonEnemies = new ArrayList<>();
        List<String> commonMatches = new ArrayList<>();
        for(QuestionUserAnswer answer : answers){
            Long questionId = answer.getQuestionId();
            Question question = questionService.getQuestion(questionId);
            if(! isRequireCal(question)){
                continue;
            }
            QuestionUserAnswer passiveAnswer = passiveAnswerMap.get(questionId).get(0);

            QuestionOption option = optionService.getOption(questionId, answer.getAnswer());
            QuestionOption passiveOption = optionService.getOption(questionId, passiveAnswer.getAnswer());
            //根据问题类型获取指定的计算器
            AnswerCalculator answerCalculator = getCalculator(question.getQuestionType());
            //计算和谐指数
            harmonyScore = harmonyScore.add(answerCalculator.calHarmony(option.getOptionScore(), option.getHarmonyWeight(), passiveOption.getOptionScore()));
            //计算话题指数
            topicScore = topicScore.add(answerCalculator.calTopic(option.getOptionScore(), option.getTopicWeight(), passiveOption.getOptionScore()));

            String commonIdol = buildCommonIdol(answer, passiveAnswer, question);
            if(commonIdol != null){
                commonIdols.add(commonIdol);
            }

            String commonEnemy = buildCommonEnemy(answer, passiveAnswer, question);
            if(StringUtils.isNotBlank(commonEnemy)){
                commonEnemies.add(commonEnemy);
            }

            String commonMatch = buildCommonMatch(answer, passiveAnswer, question);
            if(commonMatch != null){
                commonMatches.add(commonMatch);
            }
        }
        matchResultService.insert(openid, passiveOpenid, harmonyScore, topicScore, commonIdols, commonEnemies, commonMatches);
    }



    /** 构建共同的偶像 **/
    private String buildCommonIdol(QuestionUserAnswer answer, QuestionUserAnswer passiveAnswer, Question question) {
        if(question.getQuestionType().intValue() != QuestionTypeEnum.ASSESS.getKey()){
            return null;
        }
        if(!answer.getAnswer().equals(passiveAnswer.getAnswer())){
            return null;
        }
        if(!answer.getAnswer().equals(OPTION_A)){
            return null;
        }
        return question.getKeyWord();
    }

    /** 构建共同的敌人 **/
    private String buildCommonEnemy(QuestionUserAnswer answer, QuestionUserAnswer passiveAnswer, Question question) {
        if(question.getQuestionType().intValue() != QuestionTypeEnum.ASSESS.getKey()){
            return null;
        }
        if(!answer.getAnswer().equals(passiveAnswer.getAnswer())){
            return null;
        }
        if(!answer.getAnswer().equals(OPTION_E)){
            return null;
        }
        return question.getKeyWord();
    }

    /** 构建共同的赛事 **/
    private String buildCommonMatch(QuestionUserAnswer answer, QuestionUserAnswer passiveAnswer, Question question) {
        if(question.getQuestionType().intValue() != QuestionTypeEnum.WATCH_FREQUENCY.getKey()){
            return null;
        }
        if(!answer.getAnswer().equals(passiveAnswer.getAnswer())){
            return null;
        }
        if(!answer.getAnswer().equals(OPTION_A)){
            return null;
        }
        return question.getKeyWord();
    }

    /**
     * 根据问题类型选择计算方式
     */
    private AnswerCalculator getCalculator(Integer questionType) {
        return AnswerCalculatorFactory.getCalcutorFactory(questionType);
    }

    /**
     * 该问题是否需要计算.目前的策略是选择题需要计算分数
     */
    private boolean isRequireCal(Question question) {
        return QuestionFormTypeEnum.CHOICE_QUESTION.getKey() == question.getFormType().intValue();
    }
}
